package org.jflame.commons.util;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Objects;
import java.util.Set;
import java.util.StringJoiner;
import java.util.TreeSet;
import java.util.function.Function;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;

/**
 * 数组工具类
 * 
 * @author charles.zhang
 */
public abstract class ArrayHelper extends ArrayUtils {

    /**
     * 判断数组中是否包含给定字符串,忽略大小写
     * 
     * @param arr
     * @param search
     * @return
     */
    public static boolean containIgnoreCase(String[] arr, String search) {
        if (arr == null || arr.length == 0) {
            return false;
        }
        for (String s : arr) {
            if (StringHelper.equalsAnyIgnoreCase(s, search)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 创建1个元素的Integer数组
     * 
     * @param element 数组元素
     * @return
     */
    public static Integer[] of(Integer element) {
        return new Integer[] { element };
    }

    /**
     * 创建二个元素的Integer数组
     * 
     * @param element1 数组元素1
     * @param element2 数组元素2
     * @return
     */
    public static Integer[] of(Integer element1, Integer element2) {
        return new Integer[] { element1,element2 };
    }

    /**
     * 创建1个元素的int数组
     * 
     * @param element 数组元素
     * @return
     */
    public static int[] of(int element) {
        return new int[] { element };
    }

    /**
     * 创建二个元素的int数组
     * 
     * @param element1 数组元素1
     * @param element2 数组元素2
     * @return
     */
    public static int[] of(int element1, int element2) {
        return new int[] { element1,element2 };
    }

    /**
     * 创建1个元素的string数组
     * 
     * @param element
     * @return
     */
    public static String[] of(String element) {
        return new String[] { element };
    }

    @SuppressWarnings("unchecked")
    public static <T> T[] of(T element) {
        T[] arr = (T[]) Array.newInstance(element.getClass(), 1);
        arr[0] = element;
        return arr;
    }

    /**
     * 合并数组并去重,元素顺序与原数组保持一至
     * 
     * @param arr1 数组1
     * @param arr2 数组2
     * @param <T> 泛型
     * @return
     */
    public static <T> T[] union(T[] arr1, T[] arr2) {
        Set<T> newSet = new TreeSet<>();
        if (isEmpty(arr1)) {
            if (isEmpty(arr2)) {
                throw new IllegalArgumentException("arr1 and arr2 must not be empty");
            } else {
                return arr2;
            }
        } else {
            if (isEmpty(arr2)) {
                return arr1;
            } else {
                Collections.addAll(newSet, arr1);
                Collections.addAll(newSet, arr2);
                return toArray(newSet);
            }
        }
    }

    /**
     * 合并两个数组
     * 
     * @param arr1 数组1
     * @param arr2 数组2
     * @param <T> 泛型
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T[] unionAll(T[] arr1, T[] arr2) {
        if (isEmpty(arr1)) {
            if (isEmpty(arr2)) {
                throw new IllegalArgumentException("arr1 and arr2 must not be empty");
            } else {
                return ArrayUtils.clone(arr2);
            }
        } else {
            if (isEmpty(arr2)) {
                return ArrayUtils.clone(arr1);
            } else {
                T[] newArr = (T[]) Array.newInstance(arr1.getClass()
                        .getComponentType(), arr1.length + arr2.length);
                System.arraycopy(arr1, 0, newArr, 0, arr1.length);
                System.arraycopy(arr2, 0, newArr, arr1.length, arr2.length);
                return newArr;
            }
        }
    }

    /**
     * 提取集合中的某属性转为字符串数组
     * 
     * @param collection 集合
     * @param mapper 提取的属性stream操作Function
     * @return 集合某属性的字符串数组
     */
    public static <T,R> String[] toArray(Collection<T> collection, Function<? super T,? extends R> mapper) {
        CollectionHelper.requireNonEmpty(collection, "parameter 'collection' not be empty");
        return collection.stream()
                .map(mapper)
                .toArray(String[]::new);
    }

    /**
     * 集合转数组
     * 
     * @param collection
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <E> E[] toArray(Collection<E> collection) {
        E[] arr = (E[]) Array.newInstance(collection.iterator()
                .next()
                .getClass(), collection.size());
        return collection.toArray(arr);
    }

    /**
     * 判断两个数组元素是否相同,如果两个数组长度相同,任意一个元素都可以在另一数组中找到相同的元素(元素顺序可以不一致)即认为数组是相同的.
     * 
     * @param array1 数组1
     * @param array2 数组2
     * @return 如果元素相同返回true
     */
    public static <T> boolean elementEquals(T[] array1, T[] array2) {
        if (array1 == null) {
            return array2 == null;
        } else {
            if (array2 == null) {
                return false;
            }
            // 元素个数不相等
            if (array1.length != array2.length) {
                return false;
            }
            boolean equals = true;
            for (T a1 : array1) {
                if (!Arrays.stream(array2)
                        .anyMatch(a2 -> Objects.equals(a1, a2))) {
                    equals = false;
                    break;
                }
            }
            return equals;
        }
    }

    /**
     * 判断数组array2是否是数组array1的子集
     * 
     * @param array1
     * @param array2
     * @return
     */
    public static <T> boolean isSub(T[] array1, T[] array2) {
        if (array1.length < array2.length) {
            return false;
        }
        for (T a1 : array1) {
            for (T a2 : array2) {
                if (!Objects.equals(a1, a2)) {
                    return false;
                }
            }
        }
        return true;
    }

    /**
     * 字符串数组转为int数组
     * 
     * @param textArray 字符串数组,不可存在null元素
     * @return int[]
     */
    public static int[] toIntArray(String[] textArray) {
        if (isEmpty(textArray)) {
            return null;
        }
        int[] intArray = new int[textArray.length];
        for (int i = 0; i < textArray.length; i++) {
            intArray[i] = Integer.parseInt(textArray[i].trim());
        }
        return intArray;
    }

    public static Integer[] toIntegerArray(String[] textArray) {
        int[] intArray = toIntArray(textArray);
        return ArrayUtils.toObject(intArray);
    }

    /**
     * 字符串数组转为long数组
     * 
     * @param textArray 字符串数组,不可存在null元素
     * @return long[]
     */
    public static long[] toLongArray(String[] textArray) {
        if (isEmpty(textArray)) {
            return null;
        }
        long[] intArray = new long[textArray.length];
        for (int i = 0; i < textArray.length; i++) {
            intArray[i] = Long.parseLong(textArray[i].trim());
        }
        return intArray;
    }

    public static Long[] toLongObjArray(String[] textArray) {
        return toNumberArray(textArray, Long.class);
    }

    public static <T extends Number> T[] toNumberArray(String[] textArray, final Class<T> targetClass) {
        if (isEmpty(textArray)) {
            return null;
        }
        return convert(textArray, t -> NumberHelper.parseNumber(t, targetClass));
        /* T[] arr = (T[]) Array.newInstance(targetClass, textArray.length);
        for (int i = 0; i < textArray.length; i++) {
            arr[i] = NumberHelper.parseNumber(textArray[i].trim(), targetClass);
        }
        return arr;*/
    }

    /**
     * 将数组转换为指定类型的数组
     * 
     * @param <T> 源数组元素类型
     * @param <R> 目标数组元素类型
     * @param sourceArray 源数组
     * @param elementFunc 转换函数
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T,R> R[] convert(T[] sourceArray, Function<T,R> elementFunc) {
        if (isEmpty(sourceArray)) {
            return null;
        }
        R[] arr = (R[]) Array.newInstance(elementFunc.apply(sourceArray[0])
                .getClass(), sourceArray.length);
        for (int i = 0; i < sourceArray.length; i++) {
            arr[i] = elementFunc.apply(sourceArray[i]);
        }
        return arr;
    }

    /**
     * 断言非空数组,如果数组==null或empty抛出IllegalArgumentException
     *
     * @param array 数组
     * @param message 异常信息
     */
    public static <T> void requireNonEmpty(T[] array, String message) {
        if (array == null || array.length == 0) {
            throw new IllegalArgumentException(message);
        }
    }

    public static String toString(final Object[] array) {
        if (array == null) {
            return null;
        }
        if (array.length == 0) {
            return "[]";
        }
        StringJoiner joiner = new StringJoiner(",", "[", "]");
        for (Object o : array) {
            joiner.add(Objects.toString(o, StringUtils.EMPTY));
        }
        return joiner.toString();
    }
}
